﻿namespace EasyToolkit.BindingTemplates.SortAndFilter
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using EasyToolkit.BindingTemplates.Definitions;

    public class SortAndFilter<T> : ISortAndFilter
    {
        #region attributes and properties
        public ITemplateDefinition TemplateDefinition
        { get; private set; }

        public Func<T, bool> FilterMethod
        { get; private set; }

        public IEnumerable<FilterElement> Filters
        { get; private set; }

        public IEnumerable<ISortElement> Sorters
        { get; private set; }

        public Type ResultType
        { get { return typeof(T); } }
        #endregion

        #region .ctors
        public SortAndFilter(ITemplateDefinition templateDefinition, IEnumerable<FilterElement> filters, IEnumerable<ISortElement> sorters)
        {
            TemplateDefinition = templateDefinition;
            Filters = filters;
            Sorters = sorters;
            SetFilterMethod();
        }
        #endregion

        #region private methods
        private void SetFilterMethod()
        {
            if (Filters != null)
            {
                string[] filters = Filters.Where(f => !string.IsNullOrEmpty(f.FilterExpression))
                                          .Select(f => string.Format("({0})", f.FilterExpression))
                                          .ToArray();
                if (Filters.Count() > 0)
                {
                    string expressionString = string.Join(" AND ", filters);
                    Expression<Func<T, bool>> expression = System.Linq.Dynamic.DynamicExpression.ParseLambda<T, bool>(expressionString, null);
                    FilterMethod = expression.Compile();
                }
            }
        }
        #endregion

        public object ExecuteSortAndFilter(IEnumerable<object> param)
        {
            IEnumerable<T> ret = param.Cast<T>().ToList();
            if (ret != null)
            {
                if(FilterMethod != null)
                    ret = ret.Where(e => FilterMethod(e));

                if (Sorters != null)
                {
                    foreach(ISortElement sorter in Sorters)
                        ret = sorter.Sort(ret) as IEnumerable<T>;
                }
            }
            return ret;
        }
    }
}
